package com.example.socket.handler;


import com.example.socket.codec.Coder;
import com.example.socket.core.Message;
import com.example.socket.core.Request;
import com.example.socket.core.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * 消息体类型定义
 * <ul>
 * <li>用于定义 {@link Request#getBody()} / {@link Response#getBody()} 的类型， 即 {@link Message#getBody()} 的转码后类型。</li>
 * <li>request 和 response 定义允许为<code>null</code>，为<code>null</code>系统应该使用当前{@link Coder#getDefaultDecodeType()}或
 * {@link Coder#getDefaultEncodeType()}作为默认类型。</li>
 * </ul>
 */
public class TypeDefinition {

    private static final Logger logger = LoggerFactory.getLogger(TypeDefinition.class);

    /**
     * 创建类实例
     * @param format 编码格式
     * @param request 请求体类型，没有可用<code>void.class</code>代替
     * @param response 回应体类型，没有可用<code>void.class</code>代替
     * @return
     */
    public static TypeDefinition valueOf(byte format, Type request, Type response) {
        TypeDefinition result = new TypeDefinition();
        result.format = format;
        result.request = request;
        result.response = response;
        return result;
    }

    /**
     * 根据{@link Processor}实例的类型声明来创建类型定义实例
     * @param format 编码格式
     * @param handler 控制器实例
     * @return
     */
    public static TypeDefinition valueOf(byte format, Processor<?, ?> handler) {
        Class<Processor<?, ?>> clz = (Class<Processor<?, ?>>) handler.getClass();
        Type[] interfaces = clz.getGenericInterfaces();
        for (Type type : interfaces) {
            if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType().equals(Processor.class)) {
                Type[] types = ((ParameterizedType) type).getActualTypeArguments();
                return TypeDefinition.valueOf(format, types[0], types[1]);
            }
        }

        FormattingTuple message = MessageFormatter.format("无法识别的控制器声明类型[{}]", clz);
        logger.error(message.getMessage());
        throw new RuntimeException(message.getMessage());
    }

    /** 编码定义 */
    protected byte format;
    protected Type request;
    protected Type response;
    /** 方法加到同步队列执行*/
    protected String syncKey = null;
    /** 方法加到异步队列执行*/
    protected boolean async = false;
    /** 是否延迟推送*/
    protected boolean delayed = false;
    /** 不需要回复*/
    protected boolean noreply = false;

    // Getter and Setter ...

    /**
     * 获取请求体类型
     * @return
     */
    public Type getRequest() {
        return request;
    }

    /**
     * 获取编码格式
     * @return
     */
    public byte getFormat() {
        return format;
    }

    /**
     * 获取回应体类型
     * @return
     */
    public Type getResponse() {
        return response;
    }

    /**
     * 是否异步执行
     * @return
     */
    public boolean isAsync() {
        return async;
    }

    /**
     * 是否同步执行
     * @return
     */
    public boolean isSync() {
        if (syncKey != null) {
            return true;
        }
        return false;
    }

    /**
     * 获取同步键值
     * @return
     */
    public String getSyncKey() {
        return syncKey;
    }

    public boolean isDelayed() {
        return delayed;
    }

    @Override
    public String toString() {
        String s = syncKey == null ? "同步:false" : "同步:true(" + syncKey + ")";
        return "请求[类型:" + request + " " + s + "] " + "回应[类型:"
                + response + "]";
    }

    public boolean isNoreply() {
        return noreply;
    }
}
